#define _GNU_SOURCE

#include "app_bt.h"
#include <string.h>
#include "log/log.h"
#include "app_serial.h"
#include <unistd.h>

static char read_buf[1024]; // 用来缓存读取的蓝牙数据
static int read_len = 0;    // 已缓存数据的长度
static char fix_header[2] = {0xf1, 0xDD}; // 固定头

static int wait_ack(int fd){
    // 等待一定的时间（50ms）
    usleep(50 * 1000);
    // 从串口文件中读取4个字节数据，判断是否是OK\r\n
    char data_buf[4];
    read(fd, data_buf, 4);
    if (memcmp(data_buf, "OK\r\n", 4) != 0)
    {
        log_error("wait ack failed");
        return -1;
    }

    return 0;
}

static void remove_data(int num){
    memmove(read_buf, read_buf + num, read_len - num);
    read_len -= num;
}

static int bt_init_config(Device *device){
    // 初始化串口 9600 阻塞
    app_serial_init(device);

    // 修改串口为非阻塞
    app_serial_setBlock(device, 0);
    app_serial_flush(device);

    // 判断蓝牙是否可用，如果可用说明蓝牙的波特率是 9600，修改波特率/名称/NERID/MADDR，重启蓝牙
    if (app_bt_status(device) == 0)
    {
        app_bt_setBaudRate(device,BT_BR_115200);
        app_bt_rename(device, "atguigu");
        // app_bt_setNetId(device, "1315");
        // app_bt_setMaddr(device, "0011");
        app_bt_reset(device);

        // 等待重启完成
        sleep(2);
    }
    
    // 当前蓝牙的波特率是 115200，而串口是 9600，所以需要修改串口波特率为 115200
    app_serial_setBaudRate(device, BR_115200);
    app_serial_flush(device);

    // 再次判断蓝牙是否可用，如果不可用，错误退出，蓝牙初始化失败
    if (app_bt_status(device) != 0)
    {
        log_error("Bluetooth init failed");
        return -1;
    }

    app_bt_setNetId(device, "1212");
    app_bt_setMaddr(device, "0011");
    
    // 将串口改为阻塞模式
    app_serial_setBlock(device, 1);
    app_serial_flush(device);

    log_debug("Bluetooth init success");

    return 0;
}

int app_bt_init(Device *device)
{
    // 1、将蓝牙的读后处理函数和写前处理函数注传递给设备
    device->post_read = app_bt_postRead;
    device->pre_write = app_bt_preWrite;

    // 2、蓝牙连接初始化
    return bt_init_config(device);
}

int app_bt_postRead(char *data, int len)
{
    // 缓存当前读到的数据
    memcpy(read_buf + read_len, data, len);
    read_len += len;

    // 如果已缓存数据长度小于8,说明数据不完整，返回0,继续读取
    if (read_len < 8)
    {
        log_debug("read_len < 8, continue read");
        return 0;
    }
    
    // 遍历read_buf 检查已缓存数据里有没有一份完整的蓝牙数据
    int i;
    for (i = 0; i < read_len - 7; i++)
    {
        if (memcmp(fix_header, read_buf + i, 2) == 0)
        {
            if (i > 0)
            {
                // 删除前面无用的数据
                remove_data(i);
            }
            
            // 完整蓝牙数据的长度
            int blue_len = 3 + read_buf[2];
            // 如果缓存数据的长度小于完整蓝牙数据的长度，说明数据不完整，返回0,继续读取
            if (read_len < blue_len){
                log_debug("read_len < blue_len, continue read");
                return 0;
            }

            // 根据缓存的完整蓝牙数据生成字符数组保存到data中
            memset(data, 0, len);
            // conn_type id_len msg_len id msg
            data[0] = 1;    // conn_type
            data[1] = 2;    // id_len
            data[2] = read_buf[2] - 4;    // msg_len
            memcpy(data + 3, read_buf + 3, 2);    // id
            memcpy(data + 5, read_buf + 7, data[2]);    // msg

            // 删除已处理的蓝牙数据
            remove_data(blue_len);

            // 返回字符数组数据的长度
            return 3 + 2 + data[2];
        }
    }
    
    if (i > 0)
    {
        // 删除前面遍历的无效数据
        remove_data(i); 
    }

    return 0;
}

int app_bt_preWrite(char *data, int len)
{
    // 检查字符数组的长度
    if (len < 6)
    {
        log_error("data length is too short");
        return -1;
    }

    // 计算蓝牙数据的长度
    int blue_len = 12 + data[2];
    // 创建蓝牙数据数组
    char blue_data[blue_len];

    // 向blue_data 存放蓝牙数据的各个部分
    // AT+MESH
    memcpy(blue_data, "AT+MESH", 8);
    // id
    memcpy(blue_data + 8, data + 3, 2);
    // msg
    memcpy(blue_data + 10, data + 5, data[2]);
    // \r\n
    memcpy(blue_data +10 + data[2], "\r\n", 2);

    // 清空data
    memset(data, 0, len);
    // 将blue_data 拷贝到data中
    memcpy(data, blue_data, blue_len);

    // 返回蓝牙数据的长度
    return blue_len;
}

int app_bt_status(Device *device){
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char *cmd = "AT\r\n";
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_rename(Device *device, char *name){
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+NAME%s\r\n", name);
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_setBaudRate(Device *device, BT_BR baudrate){
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+BAUD%c\r\n", baudrate);
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_reset(Device *device){
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char *cmd = "AT+RESET\r\n";
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_setNetId(Device *device, char *netId){
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+NETID%s\r\n", netId);
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}

int app_bt_setMaddr(Device *device, char *maddr){
    // 向蓝牙发送指令（向串口文件中写入命令数据）
    char cmd[20];
    sprintf(cmd, "AT+MADDR%s\r\n", maddr);
    write(device->fd, cmd, strlen(cmd));

    // 等待ack
    return wait_ack(device->fd);
}
